from . import user_blueprint
from ..utils.response_util import response
from ..utils.exception import APIException
from ..utils.error_code import *
from ..models import *
from ..utils.check import *

from flask import request, session, redirect
from sqlalchemy.exc import IntegrityError, ProgrammingError
import xlrd
from functools import wraps
from math import ceil


@user_blueprint.route("/", methods=["GET", "POST"])
def main():
    return "User"


@user_blueprint.errorhandler(APIException)
def error(e):
    return APIException.to_dict(e)


@user_blueprint.route("/get_username", methods=["GET", "POST"])
def get_session_username():
    username = session.get("username")

    if username is not None:
        return response(200, "Get Username Success", session.get("username"))
    else:
        return response(400, "User Not Login", {})


@user_blueprint.route("/get_nickname", methods=["GET", "POST"])
def get_session_nickname():
    username = session.get("username")

    if username is not None:
        user = User.query.filter_by(username=username).first()
        if user is None:
            raise APIException(USERNAME_NOT_EXISTS)
        return response(200, "Get Nickname Success", user.nickname if user.nickname is not None else user.username)
    else:
        return response(400, "User Not Login", {})


@user_blueprint.route("/login", methods=["POST"])
def user_login():
    """
    用户登录
    :return:
    """
    data = get_data()
#     r = Redis.connect()  # 创建 redis 服务
    username = data.get("username")
    password = data.get("password")

    if username is None:
        raise APIException(NO_USERNAME)
    if password is None:
        raise APIException(PASSWORD_ERROR)
    user = User.query.filter(User.username == username).first()
    if user is None:
        raise APIException(USERNAME_NOT_EXISTS)
    if user.password != str(password):
        raise APIException(PASSWORD_ERROR)

    session.permanent = True
    session["username"] = str(username)
#     r.set_data(str(username))

    return response(200, "Login Success", {"user_type": user.user_type})


@user_blueprint.route("/register", methods=["POST"])
def user_register():
    """
    Register Handler(Only for students and tourists)
    :return: user_id
    """
    data = get_data()
    if data is None:
        raise APIException(USERNAME_ILLEGAL)

    # 验证 username 和 password - checkPassword
    username = data.get("username")
    if username is None:
        raise APIException(USERNAME_ILLEGAL)
    password = data.get("password")
    if password is None:
        raise APIException(PASSWORD_ILLEGAL)
    check_password = data.get("checkPassword")
    if check_password is None or check_password != password:
        raise APIException(PASSWORD_NOT_SAME)

    # 将 user 插入到数据库
    user = User(username, password, 1)
    try:
        db.session.add(user)
        db.session.commit()
    except IntegrityError:
        db.session.rollback()
        raise APIException(USERNAME_ALREADY_EXISTS)
    except Exception:
        db.session.rollback()
        raise APIException(REGISTER_ERROR)

    return response(200, "Register Success", {"username": username})


@user_blueprint.route("/import_students", methods=["POST"])
@user_is_login
@check_user_type_2
def students_import():
    """
    通过 csv/xlsx 导入学生
    :return:
    """
    user_list = []
    data = request.files.get("file", "")
    filename = data.filename
    mimetype = data.mimetype
    suffix = filename.split(".")[-1]

    if suffix == "xlsx" or suffix == "xls":
        content = xlrd.open_workbook(file_contents=data.read())
        status = content.sheet_loaded(content.sheet_names()[0])

        if status:
            data = content.sheets()[0].col_values(0)
            if data == [] or data is None:
                raise APIException(NO_USERNAME)
            for student in data:
                user = User(int(student), int(student), 1)
                user_list.append(user)
            try:
                db.session.add_all(user_list)
                db.session.commit()
            except IntegrityError as e:
                db.session.rollback()
                raise APIException(USERNAME_ALREADY_EXISTS, {"username": e.args})
            except Exception as e:
                db.session.rollback()
                raise APIException(REGISTER_ERROR, { "username": e.args})
    elif suffix == "csv":
        for student in data.readlines():
            user = User(int(student), int(student), 1)
            user_list.append(user)
        try:
            db.session.add_all(user_list)
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            raise APIException(USERNAME_ALREADY_EXISTS, {"username": int(student)})
        except Exception:
            db.session.rollback()
            raise APIException(REGISTER_ERROR, {"username": int(student)})
    else:
        raise APIException(ILLEGAL_FILE_FORMAT)

    db.session.close()

    return response(200, "Register Success", {"length": len(user_list)})


@user_blueprint.route("/delete", methods=["POST"])
@user_is_login
@check_user_type_4
def user_delete():
    """
    删除 user
    :return:
    """
    data = get_data()
    username = data.get("username")

    if username is None:
        raise APIException(NO_USERNAME)

    res = User.query.filter_by(username=username).delete()
    try:
        db.session.commit()
    except:
        db.session.rollback()
    finally:
        db.session.close()

    if res == 1:
        return response(200, "Delete Success", {"username": username})
    else:
        raise APIException(USERNAME_NOT_EXISTS, {"username": username})


@user_blueprint.route("/student/list", methods=["GET", "POST"])
@user_is_login
@check_user_type_2
def student_list():
    """
    查询学生列表
    :return:
    """
    try:
        current_page = int(request.args.get("currentPage"))
    except:
        current_page = 1
    data_per_page = 10
    r = []
    students = User.query.filter(User.user_type == 1).all()
    list_len = len(students)

    for student in students:
        tmp = dict()
        tmp["username"] = student.username
        tmp["nickname"] = student.password
        tmp["email"] = student.email
        tmp["telephone"] = student.telephone

        r.append(tmp)

    max_page_num = ceil(list_len / data_per_page)
    ret = {
        "currentPage": current_page,
        "maxPageNum": max_page_num,
        "num": list_len,
        "list": r[data_per_page * (current_page - 1): data_per_page * current_page]
    }

    return response(200, "Query Students List Success", ret)


@user_blueprint.route("/search", methods=["POST"])
@user_is_login
def user_search():
    """
    查询单个用户
    :return:
    """
    data = get_data()
    username = session.get("username")
    user = User.query.filter(User.username == username).limit(1).first()
    if data is not None and user.user_type > 1:
        username = data.get("username")
        user = User.query.filter(User.username == username).limit(1).first()

    if user is None:
        raise APIException(USERNAME_NOT_EXISTS, {"username": username})

    own_submits = UserSubmit.query.filter_by(user_id=username).order_by(-UserSubmit.create_time).all()
    right = 0
    question_ids = list()
    all_ids = list()
    if own_submits != []:
        for own_submit in own_submits:
            if own_submit.question_id not in all_ids:
                all_ids.append(own_submit.question_id)
            if own_submit.question_id not in question_ids:
                if own_submit.result == 1:
                    question_ids.append(own_submit.question_id)
                    right += 1

    ret = {
        "username": user.username,
        "nickname": user.nickname,
        "email": user.email,
        "telephone": user.telephone,
        "ipAddress": request.remote_addr,
        "rate": str(right) + "/" + str(len(all_ids)),
#        "recentAccept": [
#            {
#                "userSubmitId": own_submits[0].submit_id,
#                "questionId": own_submits[0].question_id,
#                "result": own_submits[0].result
#            }, {
#                "userSubmitId": own_submits[1].submit_id,
#                "questionId": own_submits[1].question_id,
#                "result": own_submits[1].result
#            }, {
#                "userSubmitId": own_submits[2].submit_id,
#                "questionId": own_submits[2].question_id,
#                "result": own_submits[2].result
#            }
#        ]
    }

    return response(200, "Search User Success", ret)


@user_blueprint.route("/password/reset", methods=["POST"])
@user_is_login
@check_user_type_2
def user_password_reset():
    """
    学生密码重置
    :return:
    """
    data = get_data()

    username = session.get("username")
    user = User.query.filter(User.username == username).first()

    reset_username = data.get("resetUsername")
    reset_user = User.query.filter_by(username=reset_username).first()
    if reset_user is None:
        raise APIException(USERNAME_NOT_EXISTS)
    if user.user_type != 4 and user.user_type <= reset_user.type:
        raise APIException(USERNAME_ILLEGAL)

    res = User.query.filter_by(username=reset_username).update({"password": reset_username})
    db.session.commit()
    db.session.close()

    return response(200, "User Password Reset Success", {"username": reset_username})


@user_blueprint.route("/password/update", methods=["POST"])
@user_is_login
def user_password_update():
    """
    修改用户密码
    :return:
    """
    data = get_data()
    old_password = data.get("oldPassword")
    password = data.get("password")
    check_password = data.get("checkPassword")
    username = session.get("username")

    user = User.query.filter_by(username=username).limit(1).first()

    if user is None:
        raise APIException(USERNAME_NOT_EXISTS)

    if str(old_password) != str(user.password):
        raise APIException(PASSWORD_ERROR)
    if password == "":
        raise APIException(PASSWORD_ILLEGAL)
    if password != check_password:
        raise APIException(PASSWORD_NOT_SAME)

    res = User.query.filter_by(username=username).update({"password": password})
    try:
        db.session.commit()
    except:
        db.session.rollback()
        raise APIException(UPDATE_ERROR)
    finally:
        db.session.close()

    return response(200, "User Password Update Success", {})


@user_blueprint.route("/update", methods=["POST"])
@user_is_login
def user_update():
    """
    修改用户基本信息(用户自己修改)
    :return:
    """
    data = get_data()
    username = session.get("username")
    nickname = data.get("nickname")
    email = data.get("email")
    telephone = data.get("telephone")

    user = User.query.filter(User.username == username).first()
    if user is None:
        raise APIException(USERNAME_NOT_EXISTS)

    new_data = dict()
    if nickname is None and telephone is None and email is None:
        raise APIException(NO_DATA_FOUND)
    if nickname != "" and nickname is not None:
        new_data["nickname"] = nickname
    if telephone != "" and telephone is not None:
        new_data["telephone"] = telephone
    if email != "" and email is not None:
        new_data["email"] = email

    res = User.query.filter_by(username=username).update(new_data)
    try:
        db.session.commit()
        db.session.close()
    except:
        db.session.rollback()
        raise APIException(UPDATE_ERROR)

    if res == 1:
        return response(200, "User Update Success", {})
    else:
        raise APIException(UPDATE_ERROR)


@user_blueprint.route("/teacher/list", methods=["POST"])
@user_is_login
@check_user_type_3
def teacher_list():
    """
    查询教师列表
    :return:
    """
    try:
        current_page = int(request.args.get("currentPage"))
    except:
        current_page = 1
    data_per_page = 10
    r = list()
    teachers = User.query.filter(User.user_type == 2).all()
    list_len = len(teachers)

    for teacher in teachers:
        tmp = dict()
        tmp["username"] = teacher.username
        tmp["nickname"] = teacher.password
        tmp["email"] = teacher.email
        tmp["telephone"] = teacher.telephone

        r.append(tmp)

    max_page_num = ceil(list_len / data_per_page)
    ret = {
        "currentPage": current_page,
        "maxPageNum": max_page_num,
        "num": list_len,
        "list": r[data_per_page * (current_page - 1): data_per_page * current_page]
    }
    return response(200, "Query Teachers List Success", ret)


@user_blueprint.route("/head/list", methods=["GET", "POST"])
@user_is_login
@check_user_type_4
def head_list():
    """
    查询课程负责人列表
    :return:
    """
    try:
        current_page = int(request.args.get("currentPage"))
    except:
        current_page = 1
    data_per_page = 10
    r = list()
    head_teachers = User.query.filter(User.user_type == 3).all()
    list_len = len(head_teachers)

    for head in head_teachers:
        tmp = dict()
        tmp["username"] = head.username
        tmp["nickname"] = head.password
        tmp["email"] = head.email
        tmp["telephone"] = head.telephone

        r.append(tmp)

    max_page_num = ceil(list_len / data_per_page)
    ret = {
        "currentPage": current_page,
        "maxPageNum": max_page_num,
        "num": list_len,
        "list": r[data_per_page * (current_page - 1): data_per_page * current_page]
    }

    return response(200, "Query Heads List Success", ret)


@user_blueprint.route("/manager/list", methods=["GET", "POST"])
@user_is_login
@check_user_type_4
def manager_list():
    """
    查询系统管理员列表
    :return:
    """
    try:
        current_page = int(request.args.get("currentPage"))
    except:
        current_page = 1
    data_per_page = 10
    r = list()
    managers = User.query.filter(User.user_type == 4).all()
    list_len = len(managers)

    for manager in managers:
        tmp = dict()
        tmp["username"] = manager.username
        tmp["nickname"] = manager.password
        tmp["email"] = manager.email
        tmp["telephone"] = manager.telephone
        r.append(tmp)

    max_page_num = ceil(list_len / data_per_page)
    ret = {
        "currentPage": current_page,
        "maxPageNum": max_page_num,
        "num": list_len,
        "list": r[data_per_page * (current_page - 1): data_per_page * current_page]
    }
    return response(200, "Query Managers List Success", ret)


@user_blueprint.route("/exit", methods=["GET", "POST"])
def user_exit():
    """
    用户退出登录
    :return:
    """
    session.clear()
    return response(200, "User Exit Success", {})


@user_blueprint.route("/register_manager", methods=["POST"])
@user_is_login
@check_user_type_4
def manager_register():
    """
    Register Handler(Only for managers)
    :return: user_id
    """
    data = get_data()
    if data == {} or data is None:
        raise APIException(USERNAME_ILLEGAL)

    # 验证 username 和 password - checkPassword
    username = data.get("username")
    if username is None:
        raise APIException(USERNAME_ILLEGAL)

    # 将 user 插入到数据库
    user = User(username, username, 4)
    try:
        db.session.add(user)
        db.session.commit()
    except IntegrityError:
        db.session.rollback()
        raise APIException(USERNAME_ALREADY_EXISTS)
    except Exception:
        db.session.rollback()       
        raise APIException(REGISTER_ERROR)

    return response(200, "Register Manager Success", {"username": username})


@user_blueprint.route("/register_head_teacher", methods=["POST"])
@user_is_login
@check_user_type_4
def head_teacher_register():
    """
    Register Handler(Only for head teacher)
    :return: user_id
    """
    data = get_data()

    if data == {} or data is None:
        raise APIException(USERNAME_ILLEGAL)

    # 验证 username 和 password - checkPassword
    username = data.get("username")
    if username is None:
        raise APIException(USERNAME_ILLEGAL)

    # 将 user 插入到数据库
    user = User(username, username, 3)
    try:
        db.session.add(user)
        db.session.commit()
    except IntegrityError:
        db.session.rollback()                                           
        raise APIException(USERNAME_ALREADY_EXISTS)
    except Exception:
        db.session.rollback()                                  
        raise APIException(REGISTER_ERROR)

    return response(200, "Register Head Teacher Success", {"username": username})


@user_blueprint.route("/register_teacher", methods=["POST"])
@user_is_login
@check_user_type_3
def teacher_register():
    """
    Register Handler(Only for teacher)
    :return: user_id
    """
    data = get_data()
    if data == {} or data is None:
        raise APIException(USERNAME_ILLEGAL)

    # 验证 username 和 password - checkPassword
    username = data.get("username")
    if username is None:
        raise APIException(USERNAME_ILLEGAL)

    # 将 user 插入到数据库
    user = User(username, username, 2)
    try:
        db.session.add(user)
        db.session.commit()
    except IntegrityError:
        db.session.rollback()                                           
        raise APIException(USERNAME_ALREADY_EXISTS)
    except Exception:
        db.session.rollback()                                  
        raise APIException(REGISTER_ERROR)
    finally:
        db.session.close()                      

    return response(200, "Register Teacher Success", {"username": username})


@user_blueprint.route("/submit", methods=["POST"])
@user_is_login
def own_submit():
    """
    Get own submit list
    :return:
    """
    username = session.get("username")
    r = list()

    my_submits = UserSubmit.query.filter_by(user_id=int(username)).order_by(-UserSubmit.create_time).all()
    for my_submit in my_submits:
        tmp = dict()
        tmp["submitId"] = my_submit.submit_id
        tmp["questionId"] = my_submit.question_id
        tmp["language"] = my_submit.language
        tmp["codeStatus"] = get_code_status(my_submit.code_status)
        tmp["createTime"] = str(my_submit.create_time)
        r.append(tmp)

    return response(200, "Query Onw Submit List Success", {"submitList": r})


@user_blueprint.route("/student/list/add", methods=["POST"])
@user_is_login
@check_user_type_2
def generate_student():
    """
    批量生成学生
    :return:
    """
    data = get_data()
    user_list = list()
    if data == [] or data is None:
        raise APIException(USERNAME_ILLEGAL)

    # 验证 username
    username = data.get("userList")
    if username is None:
        raise APIException(USERNAME_ILLEGAL)

    # 生成user
    for username in user_list:
        user = User(username, username, 1)
        user_list.append(user)

    # 将 user 插入到数据库
    try:
        db.session.add_all(user_list)
        db.session.commit()
    except IntegrityError:
        db.session.rollback()
        raise APIException(USERNAME_ALREADY_EXISTS)
    except Exception:
        db.session.rollback()
        raise APIException(REGISTER_ERROR)

    return response(200, "Register Student List Success", {"count": len(user_list)})

@user_blueprint.route("/get_user_type", methods=["POST"])
@user_is_login
def get_user_type():
    username = session.get("username")
    user = User.query.filter_by(username=username).limit(1).first()
    if user is None:
        raise APIException(USER_NOT_LOGIN)
    return response(200, "Get User Type Success", {"user_type": user.user_type})
